package com.rabbit.service.impl;

import com.rabbit.constant.ResultCodeEnum;
import com.rabbit.constant.MenuType;
import com.rabbit.db.entity.Menu;
import com.rabbit.db.entity.RoleMenuMapping;
import com.rabbit.db.entity.User;
import com.rabbit.exception.BusinessException;
import com.rabbit.mapper.MenuMapper;
import com.rabbit.mapper.RoleMenuMappingMapper;
import com.rabbit.service.MenuService;
import com.rabbit.vo.req.MenuReq;
import com.rabbit.vo.res.MenuRes;
import com.rabbit.vo.res.MenuTreeRes;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <h1>菜单业务实现类</h1>
 *
 * @author zjw
 * @date 2022/1/14 14:31
 */
@Service
public class MenuServiceImpl implements MenuService {

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private RoleMenuMappingMapper roleMenuMappingMapper;

    @Override
    public List<MenuRes> queryUserMenu(User user) {
        List<MenuRes> menus = menuMapper.queryUserMenu(user);
        List<MenuRes> menuResList = new ArrayList<>();
        menus.forEach(e -> {
            if (e.getMenuType().equals(MenuType.TOP) || (e.getMenuType().equals(MenuType.LEAF) && e.getParentId() == -1)) {
                MenuRes menuRes = new MenuRes();
                BeanUtils.copyProperties(e, menuRes);
                menuResList.add(menuRes);
            }
        });
        menuResList.forEach(e -> {
            List<MenuRes> children = new ArrayList<>();
            menus.forEach(k -> {
                if (e.getMenuId().equals(k.getParentId())) {
                    MenuRes menuRes = new MenuRes();
                    BeanUtils.copyProperties(k, menuRes);
                    children.add(menuRes);
                }
            });
            if (!CollectionUtils.isEmpty(children)) {
                e.setChildren(children);
            }
        });
        return menuResList;
    }

    @Override
    public List<MenuRes> queryMenuList(MenuReq menuReq) {
        Menu menu = Menu.builder().menuName(menuReq.getMenuName()).build();
        return menuMapper.queryMenuList(menu);
    }

    @Override
    public List<MenuTreeRes> queryMenuTree(MenuReq menuReq) {
        Menu menu = Menu.builder().menuName(menuReq.getMenuName()).build();
        List<MenuRes> menuResList = menuMapper.queryMenuList(menu);
        Map<String, List<MenuTreeRes>> menuResMap = menuResList.stream().map(e -> {
            MenuTreeRes menuTreeRes = new MenuTreeRes();
            menuTreeRes.setName(e.getMenuName());
            menuTreeRes.setValue(e.getMenuId());
            menuTreeRes.setParentId(e.getParentId());
            menuTreeRes.setMenuType(e.getMenuType());
            return menuTreeRes;
        }).collect(Collectors.groupingBy(item -> {
            if (Objects.equals(item.getParentId(), -1L)) {
                return "top";
            } else {
                return "other";
            }
        }));
        // 目录
        List<MenuTreeRes> resultList = new ArrayList<>(menuResMap.get("top"));
        List<MenuTreeRes> otherMenuList = menuResMap.get("other");
        resultList.forEach(e -> {
            // 菜单
            List<MenuTreeRes> leafChildren = new ArrayList<>();
            otherMenuList.forEach(k -> {
                if (Objects.equals(k.getMenuType(), MenuType.LEAF) && Objects.equals(k.getParentId(), e.getValue())) {
                    leafChildren.add(k);
                }
            });
            e.setChildren(leafChildren);
            // 资源
            leafChildren.forEach(k -> {
                List<MenuTreeRes> actionChildren = new ArrayList<>();
                otherMenuList.forEach(t -> {
                    if (Objects.equals(t.getMenuType(), MenuType.ACTION) && Objects.equals(k.getParentId(), e.getValue())) {
                        actionChildren.add(k);
                    }
                });
                k.setChildren(actionChildren);
            });
        });
        return resultList;
    }

    @Override
    public MenuRes queryMenuById(Long menuId) {
        Menu menu = menuMapper.selectByPrimaryKey(menuId);
        MenuRes menuRes = MenuRes.builder().build();
        BeanUtils.copyProperties(menu, menuRes);
        return menuRes;
    }

    @Override
    public void checkUnique(MenuReq menuReq, int operType) throws BusinessException {
        // 1. 菜单名称唯一
        Example menuNameExample = new Example(Menu.class);
        Example.Criteria menuNameCriteria = menuNameExample.createCriteria();
        menuNameCriteria.andEqualTo("menuName", menuReq.getMenuName());
        if (operType > 1) {
            menuNameCriteria.andNotEqualTo("menuId", menuReq.getMenuId());
        }
        if (menuMapper.selectCountByExample(menuNameExample) > 0) {
            throw new BusinessException(ResultCodeEnum.MENU_NAME_EXISTS_ERROR);
        }
        // 2. 类型为资源时 需要校验权限标识唯一
        if (Objects.equals(menuReq.getMenuType(), MenuType.ACTION)) {
            Example menuKeyExample = new Example(Menu.class);
            Example.Criteria menuKeyCriteria = menuKeyExample.createCriteria();
            menuKeyCriteria.andEqualTo("perms", menuReq.getPerms());
            if (operType > 1) {
                menuKeyCriteria.andNotEqualTo("menuId", menuReq.getMenuId());
            }
            if (menuMapper.selectCountByExample(menuKeyExample) > 0) {
                throw new BusinessException(ResultCodeEnum.MENU_PERMS_EXISTS_ERROR);
            }
        }
    }

    @Override
    public void checkCanBeDeleted(MenuReq menuReq) throws BusinessException {
        Menu menu = Menu.builder().parentId(menuReq.getMenuId()).build();
        if (menuMapper.selectCount(menu) > 0) {
            throw new BusinessException(ResultCodeEnum.MENU_HAS_CHILD_ERROR);
        }
        RoleMenuMapping roleMenuMapping = RoleMenuMapping.builder().menuId(menuReq.getMenuId()).build();
        if (roleMenuMappingMapper.selectCount(roleMenuMapping) > 0) {
            throw new BusinessException(ResultCodeEnum.MENU_USED_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addMenu(MenuReq menuReq) {
        Menu menu = Menu.builder().build();
        BeanUtils.copyProperties(menuReq, menu);
        menu.setCreateBy(menuReq.getOperatorUserName());
        menuMapper.insertSelective(menu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMenu(MenuReq menuReq) {
        Menu menu = Menu.builder().build();
        BeanUtils.copyProperties(menuReq, menu);
        menu.setUpdateBy(menuReq.getOperatorUserName());
        menuMapper.updateByPrimaryKeySelective(menu);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(MenuReq menuReq) {
        menuMapper.deleteByPrimaryKey(menuReq.getMenuId());
    }

}
